#include "ruleinterpreter.h"

bool Org::RuleInterpreter::scene_complies(const string &term, const bf::path &path)
{
    string regexp = "("+term+")"; // if its scene then format will be +[a-z]{3,}[0-9] eg.
    regexp.append("[0-9]{3,}");
    regex reg(regexp);

    if(regex_search(path.string(), reg))
    {
        return true;
    }
    return false;
}

bool Org::RuleInterpreter::id3_complies(const Node& node, const bf::path &dir)
{
    if(is_directory(dir))
    {
        // for slsk downloads ensure directory has no INCOMPLETE~ files
        bf::directory_iterator e_itr;
        for(bf::directory_iterator itr(dir.string()); itr!=e_itr; ++itr)
        {
            bf::path cur_path = (*itr).path();            
            if((cur_path.string()).substr(0, 10) == "INCOMPLETE~") return false;
        }

        bf::directory_iterator end_itr;
        for(bf::directory_iterator itr(dir.string()); itr!=end_itr; ++itr)
        {            
            bf::path cur_path = (*itr).path();

            if(!is_directory(cur_path) && AudioInfo::is_audio_file(cur_path.string()) )
            {
                AudioInfo info(cur_path.string());

                // for Genre v2 tags
                if(node.search_in == "GENRE")
                {             
                    regex reg("("+node.search_term+")");
                    if(regex_search(info.metadata[node.search_in], reg)) return true;
                }

                // exact match
                if(info.metadata[node.search_in] == node.search_term) return true;
            }
        }
        return false;
    }
    else if(AudioInfo::is_audio_file(dir.string()))
    {
        AudioInfo info(dir.string());
        if(info.metadata[node.search_in] == node.search_term) return true;
    }
    return false;
}

bool Org::RuleInterpreter::dir_complies(const Node& node, const bf::path &path)
{
    //string regexp = "("+term+")"; // if its scene then format will be +[a-z]{3,}[0-9] eg.
    //regexp.append("[0-9]{3,}");
    regex reg(node.search_term);

    if(regex_search(path.string(), reg)) return true;
    return false;
}




bool Org::RuleInterpreter::cond_complies(const Node& node, const bf::path &cur_path)
{
    if(node.node_type == Vars::ORG_NODE_CONDITION)
    {        
        if(node.search_type == Vars::ORG_ID3) return id3_complies(node, cur_path);
        else if(node.search_type ==Vars::ORG_SCENE) return scene_complies(node.search_term, cur_path);
        else if(node.search_type ==Vars::ORG_DIR) return dir_complies(node, cur_path);
        else return false;
    }

    if(node.node_type == Vars::ORG_NODE_BOOL)
    {
        bool node_complies = false;       

        for(vector<Node>::const_iterator i = node.child_nodes.begin(); i!=node.child_nodes.end(); ++i)
        {
            Node cur_cond = (*i);
            node_complies = RuleInterpreter::cond_complies(cur_cond, cur_path);

            if((node.operation == Vars::ORG_OR) && node_complies)
                return true; // need only one to succeed
            else if((node.operation == Vars::ORG_AND) && !node_complies)
                return false; // need only one to fail
        }
       if(node.operation == Vars::ORG_OR)
           return false; // no passes
       if(node.operation == Vars::ORG_AND)
           return true; // no fails

    }
    return true;
}



bool Org::RuleInterpreter::rule_complies(const Rule &rule, const bf::path &cur_path)
{
    // 0. ensure we have nodes
    if(rule.root_node==NULL)
            return false;

    // 1. ensure the root node is a bool node and there is only ONE
    vector<Node> nodes =  rule.root_node->child_nodes;
    if(nodes.size()<1) return false;
    Node first_node = nodes.front();

    if(nodes.size()>1 )
    {
        cout << "there should only be one root node" << endl;
        return false;
    }
    if(first_node.node_type != Vars::ORG_NODE_BOOL)
    {
        cout << "first node is not a boolean" << endl;
        return false;
    }

    //bool *complies = true;
    bool complies = cond_complies(first_node, cur_path);
    return complies;
}


